﻿using System;
using System.Collections.Generic;

namespace Independ
{
    /// <summary>
    /// Interface defining the behavior of the Unity dependency injection container.
    /// </summary>
    public interface IUnityContainer
    {
        /// <summary>
        /// Register a type mapping with the container.
        /// </summary>
        /// <typeparam name="TFrom"><see cref="Type"/> that will be requested.</typeparam>
        /// <typeparam name="TTo"><see cref="Type"/> that will actually be returned.</typeparam>
        /// <param name="name">Name of this mapping.</param>
        /// <returns>The <see cref="IUnityContainer"/> object that this method was called on.</returns>
        IUnityContainer RegisterType<TFrom, TTo>(string name = null) where TTo : TFrom;

        /// <summary>
        /// Register a type mapping with the container.
        /// </summary>
        /// <param name="from"><see cref="Type"/> that will be requested.</param>
        /// <param name="to"><see cref="Type"/> that will actually be returned.</param>
        /// <param name="name">Name of this mapping.</param>
        /// <returns>The <see cref="IUnityContainer"/> object that this method was called on.</returns>
        IUnityContainer RegisterType(Type from, Type to, string name = null);

        /// <summary>
        /// Register an instance with the container.
        /// </summary>
        /// <typeparam name="TInterface">Type of instance to register (may be an implemented interface instead of the full type).</typeparam>
        /// <param name="instance">Object to returned.</param>
        /// <param name="name">Name for registration.</param>
        /// <returns>The <see cref="IUnityContainer"/> object that this method was called on.</returns>
        IUnityContainer RegisterInstance<TInterface>(TInterface instance, string name = null);

        /// <summary>
        /// Register func with the container.
        /// </summary>
        /// <typeparam name="T"><see cref="Type"/> that will actually be returned.</typeparam>
        /// <param name="func">Func that will return <typeparamref name="T"/>.</param>
        /// <param name="name">Name for registration.</param>
        /// <returns>The <see cref="IUnityContainer"/> object that this method was called on.</returns>
        IUnityContainer Register<T>(Func<IUnityContainer, T> func, string name = null);

        /// <summary>
        /// Resolve an instance of the default requested type from the container.
        /// </summary>
        /// <typeparam name="T"><see cref="Type"/> of object to get from the container.</typeparam>
        /// <param name="name">Name of the object to retrieve.</param>
        /// <param name="resolverOverrides">Any overrides for the resolve call.</param>
        /// <returns>The retrieved object.</returns>
        T Resolve<T>(string name = null, params ParameterOverride[] resolverOverrides);

        /// <summary>
        /// Resolve an instance of the requested type with the given name from the container.
        /// </summary>
        /// <param name="t"><see cref="Type"/> of object to get from the container.</param>
        /// <param name="name">Name of the object to retrieve.</param>
        /// <param name="resolverOverrides">Any overrides for the resolve call.</param>
        /// <returns>The retrieved object.</returns>
        object Resolve(Type t, string name = null, params ParameterOverride[] resolverOverrides);

        /// <summary>
        /// Return instances of all registered types requested.
        /// </summary>
        /// <para>This method is useful if you've registered multiple types with the same <see cref="Type"/> but different names.</para>
        /// <param name="t">The type requested.</param>
        /// <returns>Set of objects of type <paramref name="t"/>.</returns>
        IEnumerable<object> ResolveAll(Type t);

        /// <summary>
        /// Return instances of all registered types requested.
        /// </summary>
        /// <typeparam name="T"><see cref="Type"/> of object to get from the container.</typeparam>
        /// <returns>Set of objects of type <typeparamref name="T"/>.</returns>
        IEnumerable<T> ResolveAll<T>();

        /// <summary>
        /// Check if a particular type/name pair has been registered with the container.
        /// </summary>
        /// <param name="type">Type to check registration for.</param>
        /// <param name="name">Name to check registration for.</param>
        /// <returns>True if this type has been registered, false if not.</returns>
        bool IsRegistered(Type type, string name = null);

        /// <summary>
        /// Check if a particular type/name pair has been registered with the container.
        /// </summary>
        /// <typeparam name="T">Type to check registration for.</typeparam>
        /// <param name="name">Name to check registration for.</param>
        /// <returns>True if this type has been registered, false if not.</returns>
        bool IsRegistered<T>(string name = null);
    }
}

